local MT = minetest
local vMod = vm_lighting_wand
local players = {}

local is_mcl = vm_lighting_wand.fsbuilder.is_mcl

math.randomseed(os.time())
local get_random = function()
  return math.random(math.random(1000, 14999), math.random(15000, 999999))
end

local get_formname = function(player)
  return vMod.tool .. ":" .. vMod.get_gui_player(player)
end

local bar = {
  bg = vMod.modname .. "_bar_bg.png^[lowpart:",
  yellow = vMod.modname .. "_bar_yellow.png",
  green = vMod.modname .. "_bar_green.png"
}
local progress_bar = function(fsb, x, y, w, h, percent, text, color)
  fsb:image(fsb:s(x + is_mcl), fsb:s(y), w, h, bar.bg .. (percent) .. ":" .. bar[color])
  fsb:tooltip(fsb:s(x + is_mcl), fsb:s(y), w, h, text .. "\n\n" .. MT.colorize("goldenrod", percent .. "%"))
end

local add_stat = function(fsb, x, y, name, value, info)
  info = info and " " .. MT.colorize("darkslategrey", info) or ""
  fsb:label(fsb:s(x) + fsb.padding, fsb:s(y) + fsb.padding, MT.colorize("grey", name))
  fsb:label(fsb:s(x + 1.5), fsb:s(y) + fsb.padding, MT.colorize("darkcyan", value) .. info)
end

local function commas(n) -- credit http://richard.warburton.it
  local left, num, right = string.match(n, "^([^%d]*%d)(%d*)(.-)$")
  return left .. (num:reverse():gsub("(%d%d%d)", "%1,"):reverse()) .. right
end

-- Wands formspec
vMod.open_gui = function(player, id)
  local fsb = vMod.fsbuilder:new({
    height = 11.75,
    theme = {
      bgcolor = "#000000BB",
      boxcolor = "#87CEFA17",
      lists = {
        normal = "#172d3a75",
        hover = "#1E90FF15",
        border = "#1E90FF40",
        tt_background = "#2F2F2F",
        tt_font = "#c1c1c1"
      },
      buttons = {
        normal = "#0E1A21",
        hover = "green",
        pressed = "#DAA520",
        alpha = "true"
      },
      color = "#c1c1c1"
    }
  })
  local p = fsb.padding

  -- If a id was given then check it
  if not player or id and vMod.get_gui_player(player) ~= id then
    vMod.close_gui(player)
    return
  end

  local player_name = player:get_player_name()
  local detached_name = vMod.detached_name(player_name)

  -- now set a id to this player
  players[player_name] = get_random()

  local is_creative_mode = vMod.is_creative_mode(player)
  local level = vMod.get_level(player)
  local levels = vMod.get_all_levels()
  local power = vMod.get_power(player)
  local max_power = vMod.get_max_power()
  local next_level = levels[level.id + 1] and levels[level.id + 1].amount_start or max_power
  local max_percent = vMod.round((power / max_power) * 100, 2)
  local level_percent = vMod.round(((power - level.amount_start) / (next_level - level.amount_start)) * 100, 2)
  local effects = vMod.get_player_effects(player)
  local effect_sound = effects.sound == "true" and "on" or "off"
  local effect_particles = effects.particles == "true" and "on" or "off"

  -- Title
  is_creative_mode = is_creative_mode and " :: " .. MT.colorize("deeppink", "Creative Mode") or ""
  fsb:label(fsb:s(0) + p, fsb:s(0.15), MT.colorize("limegreen", "Lighting Wand") .. is_creative_mode)
  -- Level
  fsb:label(fsb:s(0) + p, fsb:s(0.75), MT.colorize("goldenrod", level.name))
  -- Power
  add_stat(fsb, p, 1.50, "Power", commas(tostring(power)))
  -- Range
  add_stat(fsb, p, 2.00, "Range", level.max_range)
  -- Efficiency
  add_stat(fsb, p, 2.50, "Efficiency", (level.fuel_efficiency * 100) .. "%")
  -- Cost per use
  add_stat(fsb, p, 3.00, "Cost", level.cost_per_use, "per use")
  -- Cost per node
  add_stat(fsb, p, 3.50, "Cost", level.cost_per_node, "per node travelled")

  -- Show power % needed to level up/max
  progress_bar(fsb, 7, 0.5, 0.3, 4.75, level_percent, "Level Progress", "yellow")
  -- Show max power % bar
  progress_bar(fsb, 7.55, 0.5, 0.3, 4.75, max_percent, "Total Power", "green")

  -- Show sound and particles button
  fsb:button_tooltip(fsb:s(5.5 + is_mcl), fsb:s(1), 1, 1, "toggle_sound", effect_sound, "Toggle Sound")
  fsb:button_tooltip(fsb:s(5.5 + is_mcl), fsb:s(2), 1, 1, "toggle_particles", effect_particles, "Toggle particles")

  -- detached fuel slot
  fsb:list("detached:" .. detached_name, vMod.detached_list, fsb:s(5.5 + is_mcl), fsb:s(3), 1, 1)
  -- slot tooltip
  fsb:tooltip(fsb:s(5.5 + is_mcl), fsb:s(3), 1, 1, "Fuel Input")
  -- Players inventory
  fsb:get_player_list(0, 4.75)

  -- listring
  fsb:listring("current_player", "main")
  fsb:listring("detached:" .. detached_name, vMod.detached_list)

  --Show the formspec
  MT.show_formspec(player_name, get_formname(player), fsb:get_formspec())
end

vMod.get_gui_player = function(player)
  if not player then
    return nil
  end
  return players[player:get_player_name()] or nil
end

vMod.close_gui = function(player)
  if not player then
    return
  end
  local player_name = player:get_player_name()
  MT.close_formspec(player_name, get_formname(player))
  players[player_name] = nil
  return
end

MT.register_on_leaveplayer(
  function(player)
    players[player:get_player_name()] = nil
  end
)

local string_starts = function(s, prefix)
  return string.sub(s, 1, string.len(prefix)) == prefix
end

MT.register_on_player_receive_fields(
  function(player, formname, fields)
    -- nothing intresting skip it
    if not player or not string_starts(formname, vMod.tool) then
      return
    end

    -- its just a quit?
    if fields.quit ~= nil then
      vMod.close_gui(player)
      return
    end

    -- Take a closer look and ensure the formname matches the expected name
    if get_formname(player) ~= formname then
      vMod.close_gui(player)
      return
    end

    local effects = vMod.get_player_effects(player)
    if fields.toggle_sound ~= nil then
      local sound = effects.sound == "true" and "false" or "true"
      vMod.set_player_effects(player, "sound", sound)
    end
    if fields.toggle_particles ~= nil then
      local particles = effects.particles == "true" and "false" or "true"
      vMod.set_player_effects(player, "particles", particles)
    end
    vMod.open_gui(player, vMod.get_gui_player(player))
  end
)
